// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { Api, BrushKind, ElementInformation, GradientStop, PreviewData, PreviewDataKind, PropertyContainer, PropertyInformation, PropertyValue, PropertyValueKind } from "../api.slint";
import { StatusLineApi } from "../components/status-line.slint";
import { EditorSpaceSettings } from "../components/styling.slint";

import { BooleanWidget } from "./widgets/boolean-widget.slint";
import { CodeWidget } from "./widgets/code-widget.slint";
import { EnumWidget } from "./widgets/enum-widget.slint";
import { FloatWidget } from "./widgets/float-widget.slint";
import { IntegerWidget } from "./widgets/integer-widget.slint";
import { JsonWidget } from "./widgets/json-widget.slint";
import { MultiValueWidget } from "./widgets/multi-value-widget.slint";
import { StringWidget } from "./widgets/string-widget.slint";
import { BrushPropertyType, WindowGlobal, WindowManager } from "../windowglobal.slint";
import { InlineBrushWidget } from "widgets/inline-brush-widget.slint";

export component PropertyValueWidget inherits VerticalLayout {
    in-out property <PropertyValue> property-value;
    in property <PreviewData> preview-data;
    in property <string> property-name;
    in property <bool> enabled;
    in property <bool> has-code-action: true;
    in property <bool> has-reset-action: true;
    in property <bool> strings-are-translatable: true;
    in property <string> property-container-id;

    callback update-display-string(value: string);

    callback set-bool-binding(value: bool);
    callback set-color-binding(text: string);
    callback test-color-binding(text: string) -> bool;
    callback set-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]);
    callback test-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> bool;
    callback set-float-binding(text: string, unit: string);
    callback test-float-binding(text: string, unit: string) -> bool;
    callback set-code-binding(text: string);
    callback test-code-binding(text: string) -> bool;
    callback set-string-binding(text: string, is_translated: bool);
    callback test-string-binding(text: string, is_translated: bool) -> bool;
    callback set-enum-binding(text: string);
    callback set-current-item();

    callback reset-action();
    callback code-action();

    function update-display-string-impl(value: string) {
        self.property-value.display-string = value;
        self.update-display-string(value);
    }

    if root.property-value.kind == PropertyValueKind.boolean: BooleanWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;

        set-bool-binding(value) => {
            root.set-bool-binding(value);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }
    }

    if root.property-value.kind == PropertyValueKind.color || root.property-value.kind == PropertyValueKind.brush: InlineBrushWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;
        brush-property-type: root.property-value.kind == PropertyValueKind.color ? BrushPropertyType.color : BrushPropertyType.brush;
        preview-data <=> root.preview-data;

        update-floating-editor() => {
            return root.set-current-item();
        }

        test-color-binding(text) => {
            return (root.test-color-binding(text));
        }
        set-color-binding(text) => {
            root.set-color-binding(text);
        }

        test-brush-binding(kind, angle, color, stops) => {
            return root.test-brush-binding(kind, angle, color, stops);
        }
        set-brush-binding(kind, angle, color, stops) => {
            root.set-brush-binding(kind, angle, color, stops);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }

        reset-action() => {
            root.reset-action();
        }
        code-action() => {
            root.code-action();
        }

        init => {
            // Floating editors need to know the current property details. Call the update if something changes.
            if WindowManager.showing-color-picker && WindowManager.current-property-information.name == root.property-name {
                self.update-floating-editor();
            }
        }

    }

    if root.property-value.kind == PropertyValueKind.code: CodeWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }

        reset-action() => {
            root.reset-action();
        }
        code-action() => {
            root.code-action();
        }
    }

    if root.property-value.kind == PropertyValueKind.enum: EnumWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;

        set-enum-binding(text) => {
            root.set-enum-binding(text);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }
    }

    if root.property-value.kind == PropertyValueKind.float: FloatWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;

        test-float-binding(text, unit) => {
            return (root.test-float-binding(text, unit));
        }
        set-float-binding(text, unit) => {
            root.set-float-binding(text, unit);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }
    }

    if root.property-value.kind == PropertyValueKind.integer: IntegerWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value <=> root.property-value;

        test-integer-binding(text) => {
            return (root.test-code-binding(text));
        }
        set-integer-binding(text) => {
            root.set-code-binding(text);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }
    }

    if root.property-value.kind == PropertyValueKind.string: StringWidget {
        enabled <=> root.enabled;
        property-name <=> root.property-name;
        property-value: root.property-value;

        has-code-action: root.has-code-action;
        has-reset-action: root.has-reset-action;
        is-translatable <=> root.strings-are-translatable;

        test-string-binding(text, is_translated) => {
            return root.test-string-binding(text, is_translated);
        }
        set-string-binding(text, is_translated) => {
            root.set-string-binding(text, is_translated);
        }

        update-display-string(value) => {
            root.update-display-string-impl(value);
        }

        reset-action() => {
            root.reset-action();
        }
        code-action() => {
            root.code-action();
        }
    }
}

export component PropertyInformationWidget inherits VerticalLayout {
    in property <PropertyInformation> property-information;
    in property <ElementInformation> element-information;
    in property <bool> enabled;

    padding-bottom: EditorSpaceSettings.default-padding;
    padding-right: EditorSpaceSettings.default-padding * 2;

    PropertyValueWidget {
        property-value: root.property-information.value;
        property-name: root.property-information.name;
        enabled: root.enabled;

        set-current-item() => {
            WindowManager.show-floating-widget(property-information, element-information);
        }

        set-bool-binding(value) => {
            self.set-code-binding(value ? "true" : "false");
        }
        set-brush-binding(kind, angle, color, stops) => {
            self.set-code-binding(Api.as-slint-brush(kind, angle, color, stops));
        }
        test-brush-binding(kind, angle, color, stops) => {
            return self.test-code-binding(Api.as-slint-brush(kind, angle, color, stops));
        }
        set-color-binding(text) => {
            self.set-code-binding(text);
        }
        test-color-binding(text) => {
            return (Api.string-is-color(text));
        }
        set-enum-binding(text) => {
            self.set-code-binding(text);
        }
        test-float-binding(text, unit) => {
            return (self.test-code-binding(text + unit));
        }
        set-float-binding(text, unit) => {
            self.set-code-binding(text + unit);
        }

        set-code-binding(text) => {
            Api.set-code-binding(
                element-information.source-uri,
                element-information.source-version,
                element-information.range.start,
                property-information.name,
                text,
            );
        }
        test-code-binding(text) => {
            return (Api.test-code-binding(
                root.element-information.source-uri,
                root.element-information.source-version,
                root.element-information.range.start,
                root.property-information.name,
                text,
            ));
        }
        set-string-binding(text, is-translated) => {
            Api.set-code-binding(
                element-information.source-uri,
                element-information.source-version,
                element-information.range.start,
                property-information.name,
                text);
        }
        test-string-binding(text, is-translated) => {
            return (Api.test-code-binding(
                root.element-information.source-uri,
                root.element-information.source-version,
                root.element-information.range.start,
                root.property-information.name,
                text));
        }

        reset-action() => {
            Api.set-code-binding(
                element-information.source-uri,
                element-information.source-version,
                element-information.range.start,
                property-information.name,
                "",
            );
        }
        code-action() => {
            Api.show-document-offset-range(
                element-information.source-uri,
                Api.property-declaration-ranges(property-information.name).defined-at.expression-range.start,
                Api.property-declaration-ranges(property-information.name).defined-at.expression-range.start,
                true,
            );
        }
    }
}

export component PreviewDataPropertyValueWidget inherits VerticalLayout {
    in property <PreviewData> preview-data;
    in property <string> property-container-id;

    private property <PropertyValue> value: Api.get-property-value(root.property-container-id, root.preview-data.name);
    private property <string> possible-error;

    callback edit-in-table-editor(property-group-id: string, data: PreviewData);

    function reset-action() {
        self.set-code-binding(self.value.code);
    }

    function set-code-binding(text: string) -> bool {
        self.possible_error = Api.set-json-preview-data(root.property-container-id, root.preview-data.name, text, check-new-value(root.property-container-id + root.preview-data.name));

        StatusLineApi.help-text = self.possible-error;

        return (self.possible-error == "");
    }

    property <string> container-property-name;
    function check-new-value(value: string) -> bool {
        if container-property-name == value {
            return false;
        } else {
            container-property-name = value;
            return true;
        }
    }

    padding-bottom: EditorSpaceSettings.default-padding;
    padding-right: EditorSpaceSettings.default-padding * 2;

    if root.preview-data.kind == PreviewDataKind.Value: PropertyValueWidget {
        property-value <=> root.value;
        property-name: root.preview-data.name;
        enabled: root.preview-data.has-setter;
        property-container-id <=> root.property-container-id;
        preview-data <=> root.preview-data;

        strings-are-translatable: false;
        has-code-action: false;
        has-reset-action: false;

        set-current-item() => {
            WindowManager.show-floating-preview-widget(property-container-id, preview-data, root.value);
        }
        set-bool-binding(value) => {
            self.set-code-binding(value ? "true" : "false");
        }
        set-brush-binding(kind, angle, color, stops) => {
            self.set-code-binding(Api.as-json-brush(kind, angle, color, stops));
        }
        test-brush-binding(kind, angle, color, stops) => {
            return self.test-code-binding(Api.as-json-brush(kind, angle, color, stops));
        }
        set-color-binding(text) => {
            self.set-code-binding("\"\{text}\"");
        }
        test-color-binding(text) => {
            return (root.set-code-binding("\"\{text}\""));
        }
        set-float-binding(text, _unit) => {
            self.set-code-binding("\{text}");
        }
        test-float-binding(text, _unit) => {
            return (root.set-code-binding("\{text}"));
        }
        set-enum-binding(text) => {
            self.set-code-binding("\"\{text}\"");
        }
        set-code-binding(text) => {
            root.set-code-binding(text);
        }
        test-code-binding(text) => {
            return (root.set-code-binding(text));
        }
        set-string-binding(text, is_translated) => {
            self.test-string-binding(text, is_translated);
        }
        test-string-binding(text, is_translated) => {
            return (root.set-code-binding(is_translated ? "\"\{text}\"" : text));
        }
    }
    if root.preview-data.kind == PreviewDataKind.Table: MultiValueWidget {
        property-value <=> root.value;
        preview-data: root.preview-data;
        property-group-id: root.property-container-id;

        edit-in-table-editor(property-group-id, data) => {
            root.edit-in-table-editor(property-group-id, data);
        }
    }
    if root.preview-data.kind == PreviewDataKind.Json: JsonWidget {
        enabled: root.preview-data.has-setter;
        property-name: root.preview-data.name;
        property-value <=> root.value;

        set-code-binding(text) => {
            return (root.set-code-binding(text));
        }
    }
}
